#include "crypt_util.h"
#include "rsa_key.h"
#include "plain_blob.h"
#include "base64.h"
#include "ncrypt_mdes.h"
#include "nmalloc.h"

HCRYPTPROV MDes_hProv = 0;
HCRYPTKEY  MDes_hKey = 0;

HCRYPTPROV MDesGetProvier()
{
	HCRYPTPROV hProv = 0;
#ifdef _WIN32_WCE
	if ( !CryptAcquireContext(&hProv, 0, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) )
	{
		return 0;
	}
#else
	if ( !CryptAcquireContextA(&hProv, 0, MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) )
	{
		return 0;
	}
#endif
	return hProv;
}

HCRYPTKEY MDesGetCryptKey(HCRYPTPROV hProv)
{
	HCRYPTKEY hImportKey = 0;
	HCRYPTKEY hCryptKey = 0;
	DWORD dwMode = CRYPT_MODE_ECB;

	if ( !CreatePrivateExponentOneKey(
			hProv,
			AT_KEYEXCHANGE,
			&hImportKey) )
	{
		return 0;
	}

	if ( !ImportPlainSessionBlob(
			hProv,
			hImportKey,
			CALG_DES,
			(BYTE*)"rue3lso9",
			8,
			&hCryptKey) )
	{
		CryptDestroyKey(hImportKey);
		return 0;
	}

	if ( !CryptSetKeyParam(hCryptKey, KP_MODE, (BYTE*)&dwMode, 0) )
	{
		CryptDestroyKey(hImportKey);
		CryptDestroyKey(hCryptKey);
		return 0;
	}

	CryptDestroyKey(hImportKey);

	return hCryptKey;
}

BOOL MDesInitialize()
{
	MDes_hProv = MDesGetProvier();
	if ( !MDes_hProv )
	{
		return FALSE;
	}

	MDes_hKey = MDesGetCryptKey(MDes_hProv);
	if ( !MDes_hKey )
	{
		CryptReleaseContext(MDes_hProv, 0);
		MDes_hProv = NULL;
		return FALSE;
	}

	return TRUE;
}

void MDesFinalize()
{
	if ( MDes_hKey )
	{
		CryptDestroyKey(MDes_hKey);
		MDes_hKey	= NULL;
	}
	if ( MDes_hProv )
	{
		CryptReleaseContext(MDes_hProv, 0);
		MDes_hProv	= NULL;
	}
}

char* MDesEncrypt(char* plain)
{
	int len = strlen(plain);
	DWORD cbBuf = ((len-1)/8 + 1) * 8;
	BYTE* pbBuf = (BYTE*)malloc(cbBuf);
	char* cipher = 0;

	if ( !plain ) goto cleanup;

	memset(pbBuf, ' ', cbBuf);
	memcpy(pbBuf, plain, len);

	if ( !CryptEncrypt(MDes_hKey, 0, 0, 0,
		pbBuf, &cbBuf, cbBuf) )
	{
		goto cleanup;
	}

	cipher = EncodeBase16(pbBuf, cbBuf);

cleanup:
	if ( pbBuf ) free(pbBuf);

	return cipher;
}

char* MDesDecrypt(char* cipher)
{
	int len = 0;
	BYTE* pbTemp = DecodeBase16(cipher, strlen(cipher), &len);
	DWORD cbTemp = len;
	char* plain = (char*)malloc(cbTemp+1);
	int i = 0;

	if ( !cipher ) goto cleanup;

	memset(plain, 0, cbTemp+1);
	memcpy(plain, pbTemp, cbTemp);

	if ( !CryptDecrypt(MDes_hKey, 0, 0, 0,
		(BYTE*)plain, &cbTemp) )
	{
		plain[0] = 0;
		goto cleanup;
	}

	plain[cbTemp] = 0;

	for ( i = strlen(plain)-1 ; i >= 0 ; i-- )
	{
		if ( plain[i] == ' ' )
		{
			plain[i] = 0;
		}
		else
		{
			break;
		}
	}

cleanup:
	if ( pbTemp ) free(pbTemp);

	return plain;
}
